/**
 * 
 */
package neptune.manager.utils;

/**
 * This class creates an unsigned byte and contains methods to use this byte or
 * to make conversion with signed types
 * 
 * @author Roberto Bifulco oltremago@gmail.com
 * 
 */
public class UnsignedByte {

	int value;

	/**
	 * Creates an unsigned byte starting from an int value
	 */
	public UnsignedByte(int value) throws IllegalValueException {
		if (value > 255 || value < 0)
			throw new IllegalValueException("Number out of bounds");

		this.value = value;
	}

	/**
	 * Creates an unsigned byte starting from a signed byte value
	 * 
	 * @param value
	 */
	public UnsignedByte(byte value) throws IllegalValueException {
		if (value >= 0) {
			this.value = (int) value;
		} else if (value < 0) {
			this.value = (int) value + 256;
		}

		if (this.value > 255 || this.value < 0)
			throw new IllegalValueException("Number out of bounds");
	}

	public UnsignedByte(String value) throws IllegalValueException {
		this(Integer.parseInt(value));
	}

	/**
	 * Get the current byte value as Integer
	 * 
	 * @return the byte value rapresented as Integer
	 */
	public int getValue() {
		return value;
	}

	/**
	 * Set the byte value given its Integer rapresentation
	 * 
	 * @param value
	 * @throws IllegalValueException
	 */
	public void setValue(int value) throws IllegalValueException {
		if (value > 255 || value < 0)
			throw new IllegalValueException("Number out of bounds");

		this.value = value;
	}

	/**
	 * Set the UnsignedByte value, from a signed byte value
	 * 
	 * @param value
	 * @throws IllegalValueException
	 */
	public void setValue(byte value) throws IllegalValueException {
		if (value >= 0) {
			this.value = (int) value;
		} else if (value < 0) {
			this.value = (int) value + 256;
		}

		if (this.value > 255 || this.value < 0)
			throw new IllegalValueException("Number out of bounds");
	}

	/**
	 * Gives the unsigned byte value in signed byte rapresentation
	 * 
	 * @return
	 */
	public byte getValueInSignedByte() throws IllegalValueException {
		byte byteValue;
		if (this.value <= 127) {
			byteValue = (byte) this.value;
		} else if (this.value > 127) {
			byteValue = (byte) (this.value - 256);
		} else {
			throw new IllegalValueException("Number out of bounds");
		}
		return byteValue;
	}

	/**
	 * Converts an unsigned byte value in a signed byte value
	 * 
	 * @param byteValue
	 */
	public static byte uByteToSByte(int value) throws IllegalValueException {
		if (value > 255 || value < 0)
			throw new IllegalValueException("Number out of bounds");

		byte byteValue;

		if (value <= 127) {
			byteValue = (byte) value;
		} else if (value > 127) {
			byteValue = (byte) (value - 256);
		} else {
			throw new IllegalValueException("Number out of bounds");
		}
		return byteValue;
	}

	public String toString() {
		Integer integer = new Integer(this.value);
		return integer.toString();
	}

	/**
	 * Returns a string containing the UnsignedByte value Hesadecimal
	 * rapresentation
	 * 
	 * @return
	 */
	public String toHexRapresentation() {
		String rapresentation = "0x";

		int cipher = (this.value & 0xF0) / 16;
		rapresentation = rapresentation + this.hexEncoding(cipher);
		cipher = (this.value & 0x0F);
		rapresentation = rapresentation + this.hexEncoding(cipher);

		return rapresentation;
	}

	private String hexEncoding(int value) {

		String code = Integer.toString(value);
		switch (value) {
		case 10:
			code = "A";
			break;
		case 11:
			code = "B";
			break;
		case 12:
			code = "C";
			break;
		case 13:
			code = "D";
			break;
		case 14:
			code = "E";
			break;
		case 15:
			code = "F";
			break;
		}

		return code;
	}

	/**
	 * Incrementa il valore attuale di uno. Se il valore attuale e' 255,
	 * l'incremento portera' il valore a 0. Restituisce il nuovo valore del byte
	 * come intero.
	 * 
	 * @return
	 */
	public int increment() {
		try {
			setValue(++value);
			return value;
		} catch (IllegalValueException e) {
			value = 0;
			return value;
		}
	}

	/**
	 * Incrementa il valore attuale del valore passato come argomento. Se il
	 * valore ottenuto e' superiore a 255, viene lanciata un'eccezione.
	 * 
	 * @return
	 * @throws IllegalValueException
	 */
	public int increment(int increment) throws IllegalValueException {
		int newValue = value + increment;
		setValue(newValue);
		return value;
	}

}
